/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Windows.Forms;

namespace UserNotifier
{
    [Serializable]
    [XmlInclude(typeof(CDTrayWarnModule)),
       XmlInclude(typeof(ConsoleWarnModule)),
       XmlInclude(typeof(ExternalWarnModule)),
       XmlInclude(typeof(GammaWarnModule)),
       XmlInclude(typeof(HWBeepWarnModule)),
       XmlInclude(typeof(OSDWarnModule)),
       XmlInclude(typeof(SoundWarnModule)),
       XmlInclude(typeof(HWKeyboardBlink)),
       XmlInclude(typeof(SWKeyboardBlink)),
        XmlInclude(typeof(TeamChatWarnModule)),
    ]
    public abstract class WarnModule
    {
        private bool m_DisableSleeping = false;

        protected bool DisableSleeping
        {
            get { return m_DisableSleeping; }
            set { m_DisableSleeping = value; }
        }
        private bool m_Warning = false;

        private int m_WarnInterval = 1000;
        private Thread m_WarnThread;

        public WarnModule(int warninterval)
        {
            m_WarnInterval = warninterval;
        }

        public WarnModule()
        {
            m_WarnInterval = 5000;
        }

        ~WarnModule()
        {
            Stop();
        }
    
        public int WarnInterval
        {
            get
            {
                return m_WarnInterval;
            }
            set
            {
                m_WarnInterval = value;
            }
        }

        [Browsable(false)]
        public abstract WarnModuleTypes Type
        {
            get;
        }

        [Browsable(false)]
        public abstract string Description
        {
            get;
        }

        [Browsable(false)]
        public virtual string Name
        {
            get
            {
                return Enum.GetName(typeof(WarnModuleTypes), Type);
            }
        }

        protected abstract void Warn();
        public virtual void Test()
        {
            Warn();
        }

        public virtual void OnGameProcessChanged(System.Diagnostics.Process process)
        {
            //nothing
        }

        protected virtual bool InitDelegate()
        {
            //return true to continue execution
            return true;
        }

        protected virtual void CleanupDelegate()
        {
            //nothing
        }

        private void WarnDelegate()
        {
            if (InitDelegate())
            {
                while (m_Warning)
                {
                    Warn();
                    if (!DisableSleeping)
                        Thread.Sleep(m_WarnInterval);
                }
            }
            CleanupDelegate();
            m_WarnThread = null;
        }
        protected void StartThread()
        {
            if (m_WarnThread == null || m_WarnThread.ThreadState == System.Threading.ThreadState.Aborted || m_WarnThread.ThreadState == System.Threading.ThreadState.Stopped)
            {
                m_Warning = true;
                m_WarnThread = new Thread(new ThreadStart(WarnDelegate));
                m_WarnThread.Name = Enum.GetName(this.Type.GetType(), this.Type) + "-Thread";
                m_WarnThread.IsBackground = true;
                m_WarnThread.Start();
            }
        }
        protected void StopThread()
        {
            DateTime start = DateTime.Now;
            while (m_WarnThread != null && (m_WarnThread.ThreadState != System.Threading.ThreadState.Stopped) && DateTime.Now.Subtract(start).TotalMilliseconds < 1000)
            {
                m_Warning = false;
                Thread.Sleep(50);
            }
            if (m_WarnThread != null && m_WarnThread.ThreadState != System.Threading.ThreadState.Stopped)
            {
                try
                {
                    m_WarnThread.Abort();
                }
                catch { }
            }
        }

        private WarnEvents m_AssignedEvents = WarnEvents.None;
        [Browsable(false)]
        public WarnEvents AssignedEvents
        {
            get { return m_AssignedEvents; }
            set
            {
                if ((value & m_ActiveEvents) != (m_ActiveEvents & m_AssignedEvents))
                    EventsChanged(value & m_ActiveEvents);
                m_AssignedEvents = value;
            }
        }

        public void Stop()
        {
            ActiveEvents = WarnEvents.None;
            StopThread();
        }

        public bool isAssigned(WarnEvents ev)
        {
            return (ev & m_AssignedEvents) != 0;
        }

        public bool isAssignedAndActive(WarnEvents ev)
        {
            return (ev & m_AssignedEvents & m_ActiveEvents) != 0;
        }

        private WarnEvents m_ActiveEvents = WarnEvents.None;
        [Browsable(false)]
        [XmlIgnore]
        public WarnEvents ActiveEvents
        {
            get { return m_ActiveEvents; }
            set
            {
                if ((value & m_AssignedEvents) != (m_ActiveEvents & m_AssignedEvents))
                    EventsChanged(value & m_AssignedEvents);
                m_ActiveEvents = value;
            }
        }

        protected virtual void EventsChanged(WarnEvents newActiveEvents)
        {
            //nothing
            if (newActiveEvents != WarnEvents.None)
                StartThread();
            else
                StopThread();
        }
    }



    public abstract class BaseTestClass
    {
        public BaseTestClass()
        {
            //nothing
        }
        protected abstract void Test();
        public virtual void ThrowException()
        {
            Test();
        }
    };

    
}
